package get

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/urfave/cli/v2"
	"gluenet/internal/client/util"
	"gopkg.in/yaml.v3"
	"time"
	"unicode"
)

type InstanceBody struct {
	Code    int            `json:"code" yaml:"code"`
	Message string         `json:"message" yaml:"message"`
	Data    []InstanceData `json:"data" yaml:"data"`
}

type InstanceData struct {
	Guid         string        `json:"guid" yaml:"guid"`
	Name         string        `json:"name" yaml:"name"`
	ConfigId     string        `json:"config_id" yaml:"config_id"`
	Label        string        `json:"label" yaml:"label"`
	Version      string        `json:"version" yaml:"version"`
	Describe     string        `json:"describe" yaml:"describe"`
	Platform     string        `json:"platform" yaml:"platform"`
	Origin       string        `json:"origin" yaml:"origin"`
	Kind         string        `json:"kind" yaml:"kind"`
	Links        []interface{} `json:"links" yaml:"links"`
	DetailValue  interface{}   `json:"detail_value" yaml:"detail_value"`
	RuntimeValue interface{}   `json:"runtime_value" yaml:"runtime_value"`
	CreateTime   string        `json:"create_time" yaml:"create_time"`
	UpdateTime   string        `json:"update_time" yaml:"update_time"`
}

type RuntimeValue struct {
	Agents     string      `json:"agents" yaml:"agents"`
	Containers interface{} `json:"containers" yaml:"containers"`
	Platform   string      `json:"platform" yaml:"platform"`
	Spec       interface{} `json:"spec,omitempty" yaml:"spec,omitempty`
	State      interface{} `json:"state" yaml:"state"`
}

func instance(ctx *cli.Context) error {
	body, err := util.HttpRequest("GET", cliUrl+"/apis/instance/all", nil)
	if err != nil {
		return err
	}

	err = parseInstance(ctx, body)
	//fmt.Println(string(body))
	return nil
}

func parseInstance(ctx *cli.Context, body []byte) error {
	var (
		instanceBody InstanceBody
		idName       string
		filetype     string
	)

	err := json.Unmarshal(body, &instanceBody)
	if err != nil {
		return err
	}

	if ctx.Bool("all") {
		fmt.Printf("%-40s %-25s %-15s %-10s %-30s\n",
			"Guid", "Name", "Platform", "Age", "Label")
		fmt.Println("---------------------------------------------------------------------------" +
			"-----------------------------------------------------")
	} else {
		idName = ctx.String("id")
		filetype = ctx.String("output")
	}

	for _, instanceData := range instanceBody.Data {
		if ctx.Bool("all") {
			listInstanceInfo(instanceData)
		} else if ctx.Bool("containers") && (instanceData.Guid == idName || instanceData.Name == idName) {
			var runtimeValue RuntimeValue
			jsonRuntimeValue, _ := json.Marshal(instanceData.RuntimeValue)
			err = json.Unmarshal(jsonRuntimeValue, &runtimeValue)
			if err != nil {
				return err
			}
			yamlContainers, _ := yaml.Marshal(runtimeValue.Containers)

			fmt.Println("--------------------------------------------------")
			fmt.Println("* Instance name :" + instanceData.Name)
			fmt.Println("* Id :" + instanceData.Guid)
			fmt.Println(string(yamlContainers))
		} else if instanceData.Guid == idName || instanceData.Name == idName {
			var outString string
			switch filetype {
			case "yaml":
				yamlByte, _ := yaml.Marshal(instanceData)
				outString = string(yamlByte)
			case "json":
				jsonByte, _ := json.Marshal(instanceData)
				outString = string(jsonByte)
			default:
				err = errors.New("wrong config argument: please type \"json\" or \"yaml\"")
				return err
			}

			fmt.Print(outString)
			break
		}
	}
	return nil
}

func listInstanceInfo(instanceData InstanceData) {
	var name []byte
	nameLen := 25

	if len(instanceData.Name) < nameLen {
		cnt := 0
		for _, c := range instanceData.Name {
			if unicode.Is(unicode.Han, c) {
				cnt++
			}
		}

		slice := make([]byte, nameLen+cnt-len(instanceData.Name))
		for k := range slice {
			slice[k] = ' '
		}
		name = append([]byte(instanceData.Name), slice...)
	}

	createTime, _ := time.Parse("2006-01-02T15:04:05Z", instanceData.CreateTime)
	age := int(time.Now().Sub(createTime).Hours())
	var ageFmt string
	if age == 0 {
		ageFmt = "<1h"
	} else if age < 24 {
		ageFmt = fmt.Sprintf("%dh", age%24)
	} else {
		ageFmt = fmt.Sprintf("%dd %dh", age/24, age%24)
	}

	fmt.Printf("%-40s %s %-15s %-15s %-30s\n",
		instanceData.Guid, string(name), instanceData.Platform, ageFmt, instanceData.Label)
}
